package com.banfan.almond.web.security;

import com.banfan.almond.base.global.ECode;
import com.banfan.almond.utils.RedisUtil;
import com.banfan.almond.utils.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

@Component
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        String requestURI = request.getRequestURI();
        if (requestURI.startsWith("/api/auth/")){
            log.info("验证token : URI : {} | 结果 : {}",requestURI,"不验证");
            filterChain.doFilter(request,response);
            return;
        }

        //获取jwt
        String clientJwt = request.getHeader("Authorization");

        try {
            //解析jwt获取payload信息(获取私钥)
            String clientUsername = JwtUtil.getUsername(clientJwt);
            //有效jwt，从内存拿jwt
            String serverJwt = redisUtil.get(clientUsername);
//            String serverUsername = JwtUtil.getUsername(serverJwt);

            //验证成功
            if (clientUsername != null && serverJwt != null) {
                //create userDetail
                UserDetails userDetails = this.userDetailsService.loadUserByUsername(clientUsername);
                //create authentication token that need user/credential/authorities
                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(
                                userDetails,
                                null,
                                userDetails.getAuthorities()
                        );
                authentication.setDetails(
                        new WebAuthenticationDetailsSource().buildDetails(request)
                );

                SecurityContextHolder.getContext().setAuthentication(authentication);



                log.info("验证token : URI : {} | 结果 : {}",requestURI,"验证通过");
                filterChain.doFilter(request, response);
                return;

            }else{
                //继续过滤链
                log.info("验证token : URI : {} | 结果 : {}",requestURI,"失败 not found Authorization or Authorization 失效");
                needLogin(response);
                return;
            }

        }catch (IllegalArgumentException e){
            log.info("验证token : URI : {} | 结果 : {}",requestURI,"失败 IllegalArgumentException");
            needLogin(response);
            return;
        }catch (NullPointerException e){
            log.info("验证token : URI : {} | 结果 : {}",requestURI,"失败 NullPointerException");
            needLogin(response);
            return;
        }

    }

    public void needLogin(HttpServletResponse response) throws IOException {
        ServletOutputStream outputStream = response.getOutputStream();
//        response.setStatus(401);
        String result = ResultUtil.resultWithMessage(ECode.UNAUTHORIZED,"未通过token验证");
        outputStream.write(result.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        outputStream.close();
    }
}
